package edu.cuit.avatar.common;

import edu.cuit.avatar.annotations.TableField;
import edu.cuit.avatar.common.converter.ConverterRegister;
import lombok.extern.slf4j.Slf4j;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

/**
 * @author <a href="mailto:1020zhaodan@163.com">Adan</a>
 * @version 1.0
 * @date 2025/7/26 9:27
 */
@Slf4j
public class BeanUtils {
    public static<T> T map2bean(Map<String,?> map, Class<T> clazz){
        if(map == null || clazz == null) return null;
        T result = null;
        try {
            //通过反射调用JavaBean默认的构造方法创建其类型实例对象 result = new Student()
            result = clazz.getDeclaredConstructor().newInstance();
            BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class);
            PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
            for(var pd : pds){
                //对属性注解进行处理
                TableField field = pd.getReadMethod().getAnnotation(TableField.class);
                //默认的约定: 属性名(驼峰createTime)=map中的key(create_time)
                String key = StringUtils.mapCamelCaseToUnderscore(field == null ? pd.getName() : field.name());
                var setter = pd.getWriteMethod();
                if(setter != null && map.containsKey(key)){
                    Object value = map.get(key);
                    if(value == null)
                        continue;

                    //value的类型和属性的类型不一致，需要进行类型转换
                    if(!pd.getPropertyType().isAssignableFrom(value.getClass())){
                        log.info("类型转换=>属性名:{}, value的类型：{}, 属性类型:{}", pd.getName(), value.getClass().getName(), pd.getPropertyType().getName());
                        //类型转换器(将源类型转换为目标类型)
                        //根据属性类型获取对应的类型转换其进行类型转换
                        var converter = ConverterRegister.getConverter(pd.getPropertyType());
                        value = converter.convert(value);
                    }

                    //调用setter方法完成属性设值 result.setSsn(value)
                    setter.invoke(result, value);
                }
            }
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException |
                 IntrospectionException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
        return result;
    }
}
